module fp16_acc #(
    parameter int INPUTS          = 8,  // 输入数量 (主要可配置参数)
    parameter int PIPELINE_STAGES = 4   // 流水线级数
) (
    input  logic                 clk,
    input  logic                 rst_n,
    input  logic                 valid_in,   // 输入有效信号
    input  logic [INPUTS*16-1:0] operands,   // FP16输入数据
    output logic                 valid_out,  // 输出有效信号
    output logic [         31:0] result,     // FP32累加结果
    output logic                 exception   // 异常标志
);

    // IEEE 754 半精度浮点数输入参数
    localparam int IN_DWIDTH = 16;  // 输入数据位宽 (FP16)
    localparam int IN_EWIDTH = 5;  // 输入指数位宽
    localparam int IN_MWIDTH = 10;  // 输入尾数位宽
    localparam int IN_BIAS = 15;  // 输入指数偏移量

    // IEEE 754 单精度浮点数输出参数
    localparam int OUT_DWIDTH = 32;  // 输出数据位宽 (FP32)
    localparam int OUT_EWIDTH = 8;  // 输出指数位宽
    localparam int OUT_MWIDTH = 23;  // 输出尾数位宽
    localparam int OUT_BIAS = 127;  // 输出指数偏移量

    localparam int RWIDTH = 16;  // 舍入位宽度 (增加精度)

    // 计算衍生参数 - 基于FP32输出格式
    localparam int IN_SIGNIFICAND_WIDTH = IN_MWIDTH + 1;  // 输入尾数位宽(含隐含位) = 11
    localparam int OUT_SIGNIFICAND_WIDTH = OUT_MWIDTH + 1;  // 输出尾数位宽(含隐含位) = 24
    localparam int ALIGNED_WIDTH = OUT_SIGNIFICAND_WIDTH + RWIDTH;  // 对阶后尾数位宽 = 40
    localparam int GUARD_BITS = 4;  // 保护位：增加到4位以处理更多输入
    localparam int CSA_WIDTH = ALIGNED_WIDTH + GUARD_BITS + 1;  // CSA树输入位宽 = 45
    localparam int LOD_WIDTH = $clog2(CSA_WIDTH);  // LOD输出位宽 = 6

    localparam int MAX_IN_EXP = (1 << IN_EWIDTH) - 1;  // 输入最大指数值 = 31
    localparam int MAX_OUT_EXP = (1 << OUT_EWIDTH) - 1;  // 输出最大指数值 = 255
    localparam logic [IN_EWIDTH-1:0] IN_EXP_ZEROS = '0;  // 输入全零指数
    localparam logic [IN_EWIDTH-1:0] IN_EXP_ONES = '1;  // 输入全一指数
    localparam logic [OUT_EWIDTH-1:0] OUT_EXP_ZEROS = '0;  // 输出全零指数
    localparam logic [OUT_EWIDTH-1:0] OUT_EXP_ONES = '1;  // 输出全一指数
    localparam logic [IN_MWIDTH-1:0] IN_MANT_ZEROS = '0;  // 输入全零尾数
    localparam logic [OUT_MWIDTH-1:0] OUT_MANT_ZEROS = '0;  // 输出全零尾数
    localparam logic [31:0] NAN = 32'h7fc00000;  // FP32 NaN值

    // IEEE 754 输入类型定义
    typedef struct packed {
        logic                 sign;
        logic [IN_EWIDTH-1:0] exponent;
        logic [IN_MWIDTH-1:0] mantissa;
    } ieee754_fp16_t;

    // IEEE 754 输出类型定义
    typedef struct packed {
        logic                  sign;
        logic [OUT_EWIDTH-1:0] exponent;
        logic [OUT_MWIDTH-1:0] mantissa;
    } ieee754_fp32_t;

    // 特殊值检测结构
    typedef struct packed {
        logic is_inf;
        logic is_nan;
        logic is_zero;
        logic is_subnormal;
    } special_flags_t;

    // 流水线级之间的寄存器
    // Stage 1: 数据解包和特殊值检测
    logic                                      valid_s1;
    ieee754_fp16_t                             operand_array_s1[INPUTS];
    logic           [          OUT_EWIDTH-1:0] exponents_s1    [INPUTS];  // 转换为FP32指数范围
    logic           [IN_SIGNIFICAND_WIDTH-1:0] significands_s1 [INPUTS];
    logic                                      signs_s1        [INPUTS];
    special_flags_t                            special_flags_s1[INPUTS];
    logic [INPUTS-1:0] is_inf_s1, is_nan_s1, is_zero_s1;
    logic [INPUTS-1:0] pos_inf_s1, neg_inf_s1;

    // Stage 2: 最大指数查找和对阶
    logic                               valid_s2;
    logic           [   OUT_EWIDTH-1:0] max_exponent_s2;
    logic           [ALIGNED_WIDTH-1:0] aligned_significands_s2[INPUTS];
    logic                               signs_s2               [INPUTS];
    special_flags_t                     special_flags_s2       [INPUTS];
    logic [INPUTS-1:0] is_inf_s2, is_nan_s2, is_zero_s2;
    logic [INPUTS-1:0] pos_inf_s2, neg_inf_s2;

    // Stage 3: CSA树计算
    logic valid_s3;
    logic [CSA_WIDTH-1:0] csa_sum_s3, csa_carry_s3;
    logic signed [CSA_WIDTH-1:0] accumulator_s3;
    logic [INPUTS-1:0] is_inf_s3, is_nan_s3, is_zero_s3;
    logic [INPUTS-1:0] pos_inf_s3, neg_inf_s3;
    logic [OUT_EWIDTH-1:0] max_exponent_s3;

    // Stage 4: 规格化和舍入
    logic                  valid_s4;
    logic                  result_sign_s4;
    logic [ CSA_WIDTH-1:0] abs_accumulator_s4;
    logic [ LOD_WIDTH-1:0] first_one_pos_s4;
    logic                  no_ones_flag_s4;
    logic [INPUTS-1:0] is_inf_s4, is_nan_s4, is_zero_s4;
    logic [INPUTS-1:0] pos_inf_s4, neg_inf_s4;
    logic        [      OUT_EWIDTH-1:0] max_exponent_s4;

    // 临时信号
    logic        [      OUT_EWIDTH-1:0] valid_exponents       [INPUTS];
    logic        [      OUT_EWIDTH-1:0] exp_diffs             [INPUTS];
    logic signed [       CSA_WIDTH-1:0] signed_significands   [INPUTS];
    logic        [       CSA_WIDTH-1:0] csa_tree_in           [INPUTS];
    logic        [INPUTS*CSA_WIDTH-1:0] csa_tree_input_packed;
    logic [CSA_WIDTH-1:0] csa_sum, csa_carry;

    // 最大指数查找的中间信号
    logic [OUT_EWIDTH-1:0] max_exp_stage1[INPUTS/2];
    logic [OUT_EWIDTH-1:0] max_exp_stage2[INPUTS/4];

    // ==================== Stage 1: 数据解包和特殊值检测 ====================
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            valid_s1 <= '0;
            for (int i = 0; i < INPUTS; i++) begin
                operand_array_s1[i] <= '0;
                signs_s1[i]         <= '0;
                exponents_s1[i]     <= '0;
                significands_s1[i]  <= '0;
                special_flags_s1[i] <= '0;
            end
            is_inf_s1  <= '0;
            is_nan_s1  <= '0;
            is_zero_s1 <= '0;
            pos_inf_s1 <= '0;
            neg_inf_s1 <= '0;
        end else begin
            valid_s1 <= valid_in;

            for (int i = 0; i < INPUTS; i++) begin
                operand_array_s1[i] <= operands[i*IN_DWIDTH+:IN_DWIDTH];

                // 提取IEEE 754字段
                signs_s1[i] <= operands[i*IN_DWIDTH+15];

                // 检查特殊值
                special_flags_s1[i].is_inf <= (&operands[i*IN_DWIDTH + 14 -: IN_EWIDTH]) & 
                                             (~|operands[i*IN_DWIDTH + 9 -: IN_MWIDTH]);
                special_flags_s1[i].is_nan <= (&operands[i*IN_DWIDTH + 14 -: IN_EWIDTH]) & 
                                             (|operands[i*IN_DWIDTH + 9 -: IN_MWIDTH]);
                special_flags_s1[i].is_zero <= (~|operands[i*IN_DWIDTH + 14 -: IN_EWIDTH]) & 
                                              (~|operands[i*IN_DWIDTH + 9 -: IN_MWIDTH]);
                special_flags_s1[i].is_subnormal <= (~|operands[i*IN_DWIDTH + 14 -: IN_EWIDTH]) & 
                                                   (|operands[i*IN_DWIDTH + 9 -: IN_MWIDTH]);

                // 处理隐含位：规格化数隐含位为1，非规格化数为0
                significands_s1[i] <= (|operands[i*IN_DWIDTH + 14 -: IN_EWIDTH]) ? 
                                     {1'b1, operands[i*IN_DWIDTH + 9 -: IN_MWIDTH]} :
                                     {1'b0, operands[i*IN_DWIDTH + 9 -: IN_MWIDTH]};

                // 指数转换：FP16转FP32（调整偏移量）
                if (|operands[i*IN_DWIDTH+14-:IN_EWIDTH]) begin
                    // 规格化数：调整偏移量从15到127
                    exponents_s1[i] <= operands[i*IN_DWIDTH+14-:IN_EWIDTH] - IN_BIAS + OUT_BIAS;
                end else if ((~|operands[i*IN_DWIDTH+14-:IN_EWIDTH]) & (|operands[i*IN_DWIDTH+9-:IN_MWIDTH])) begin
                    // 非规格化数：转换为规格化FP32
                    exponents_s1[i] <= 1 - IN_BIAS + OUT_BIAS;  // = 113
                end else begin
                    // 零值
                    exponents_s1[i] <= '0;
                end

                // 特殊值标志
                is_inf_s1[i] <= (&operands[i*IN_DWIDTH+14-:IN_EWIDTH]) & (~|operands[i*IN_DWIDTH+9-:IN_MWIDTH]);
                is_nan_s1[i] <= (&operands[i*IN_DWIDTH+14-:IN_EWIDTH]) & (|operands[i*IN_DWIDTH+9-:IN_MWIDTH]);
                is_zero_s1[i] <= (~|operands[i*IN_DWIDTH+14-:IN_EWIDTH]) & (~|operands[i*IN_DWIDTH+9-:IN_MWIDTH]);

                // 正负无穷标志
                pos_inf_s1[i] <= (&operands[i*IN_DWIDTH + 14 -: IN_EWIDTH]) & 
                                (~|operands[i*IN_DWIDTH + 9 -: IN_MWIDTH]) & 
                                (~operands[i*IN_DWIDTH + 15]);
                neg_inf_s1[i] <= (&operands[i*IN_DWIDTH + 14 -: IN_EWIDTH]) & 
                                (~|operands[i*IN_DWIDTH + 9 -: IN_MWIDTH]) & 
                                (operands[i*IN_DWIDTH + 15]);
            end
        end
    end

    // ==================== Stage 2: 最大指数查找和对阶 ====================
    // 最大指数查找的组合逻辑（排除特殊值）
    logic [OUT_EWIDTH-1:0] max_exponent_comb;

    always_comb begin
        for (int i = 0; i < INPUTS; i++) begin
            // 只有非特殊值的指数参与最大值查找
            valid_exponents[i] = (is_inf_s1[i] | is_nan_s1[i]) ? '0 : exponents_s1[i];
        end
    end

    generate
        if (INPUTS == 4) begin : gen_max_exp_4
            always_comb begin
                // 第一级比较
                for (int i = 0; i < INPUTS / 2; i++) begin
                    max_exp_stage1[i] = (valid_exponents[i*2] > valid_exponents[i*2+1]) ? 
                                       valid_exponents[i*2] : valid_exponents[i*2+1];
                end

                // 第二级比较
                max_exponent_comb = (max_exp_stage1[0] > max_exp_stage1[1]) ? max_exp_stage1[0] : max_exp_stage1[1];
            end
        end else if (INPUTS == 8) begin : gen_max_exp_8
            always_comb begin
                // 第一级比较
                for (int i = 0; i < INPUTS / 2; i++) begin
                    max_exp_stage1[i] = (valid_exponents[i*2] > valid_exponents[i*2+1]) ? 
                                       valid_exponents[i*2] : valid_exponents[i*2+1];
                end

                // 第二级比较
                for (int i = 0; i < INPUTS / 4; i++) begin
                    max_exp_stage2[i] = (max_exp_stage1[i*2] > max_exp_stage1[i*2+1]) ? 
                                       max_exp_stage1[i*2] : max_exp_stage1[i*2+1];
                end

                // 第三级比较
                max_exponent_comb = (max_exp_stage2[0] > max_exp_stage2[1]) ? max_exp_stage2[0] : max_exp_stage2[1];
            end
        end else begin : gen_max_exp_default
            // 对于其他输入数量，使用简单的循环比较
            always_comb begin
                max_exponent_comb = valid_exponents[0];
                for (int i = 1; i < INPUTS; i++) begin
                    if (valid_exponents[i] > max_exponent_comb) begin
                        max_exponent_comb = valid_exponents[i];
                    end
                end
            end
        end
    endgenerate

    // 对阶计算组合逻辑
    logic [ALIGNED_WIDTH-1:0] aligned_significands_comb[INPUTS];
    always_comb begin
        for (int i = 0; i < INPUTS; i++) begin
            exp_diffs[i] = max_exponent_comb - exponents_s1[i];

            // 特殊值不参与对阶
            if (is_inf_s1[i] | is_nan_s1[i] | is_zero_s1[i]) begin
                aligned_significands_comb[i] = '0;
            end else begin
                // 对阶移位，使用参数化的移位量限制
                if (exp_diffs[i] > ALIGNED_WIDTH - 1) begin
                    aligned_significands_comb[i] = '0;
                end else begin
                    // FP16的11位尾数扩展到FP32的40位对阶宽度
                    logic [ALIGNED_WIDTH-1:0] extended_significand;
                    extended_significand         = {significands_s1[i], {(RWIDTH + OUT_MWIDTH - IN_MWIDTH) {1'b0}}};
                    aligned_significands_comb[i] = extended_significand >> exp_diffs[i];
                end
            end
        end
    end

    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            valid_s2        <= '0;
            max_exponent_s2 <= '0;
            for (int i = 0; i < INPUTS; i++) begin
                aligned_significands_s2[i] <= '0;
                signs_s2[i]                <= '0;
                special_flags_s2[i]        <= '0;
            end
            is_inf_s2  <= '0;
            is_nan_s2  <= '0;
            is_zero_s2 <= '0;
            pos_inf_s2 <= '0;
            neg_inf_s2 <= '0;
        end else begin
            valid_s2        <= valid_s1;
            max_exponent_s2 <= max_exponent_comb;

            for (int i = 0; i < INPUTS; i++) begin
                aligned_significands_s2[i] <= aligned_significands_comb[i];
                signs_s2[i]                <= signs_s1[i];
                special_flags_s2[i]        <= special_flags_s1[i];
            end

            is_inf_s2  <= is_inf_s1;
            is_nan_s2  <= is_nan_s1;
            is_zero_s2 <= is_zero_s1;
            pos_inf_s2 <= pos_inf_s1;
            neg_inf_s2 <= neg_inf_s1;
        end
    end

    // ==================== Stage 3: CSA树计算 ====================
    // 补码转换组合逻辑
    always_comb begin
        for (int i = 0; i < INPUTS; i++) begin
            logic [CSA_WIDTH-1:0] extended_significand;
            extended_significand = {{GUARD_BITS + 1{1'b0}}, aligned_significands_s2[i]};

            // 使用条件赋值简化补码转换
            signed_significands[i] = signs_s2[i] ? (~extended_significand + 1'b1) : extended_significand;

            csa_tree_in[i] = signed_significands[i];
            csa_tree_input_packed[i*CSA_WIDTH+:CSA_WIDTH] = csa_tree_in[i];
        end
    end

    // CSA树实例化
    acc_csa_tree #(
        .num_inputs (INPUTS),
        .input_width(CSA_WIDTH)
    ) u_acc_csa_tree (
        .INPUT(csa_tree_input_packed),
        .OUT0 (csa_sum),
        .OUT1 (csa_carry)
    );

    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            valid_s3        <= '0;
            csa_sum_s3      <= '0;
            csa_carry_s3    <= '0;
            accumulator_s3  <= '0;
            max_exponent_s3 <= '0;
            is_inf_s3       <= '0;
            is_nan_s3       <= '0;
            is_zero_s3      <= '0;
            pos_inf_s3      <= '0;
            neg_inf_s3      <= '0;
        end else begin
            valid_s3        <= valid_s2;
            csa_sum_s3      <= csa_sum;
            csa_carry_s3    <= csa_carry;
            accumulator_s3  <= csa_sum + csa_carry;
            max_exponent_s3 <= max_exponent_s2;
            is_inf_s3       <= is_inf_s2;
            is_nan_s3       <= is_nan_s2;
            is_zero_s3      <= is_zero_s2;
            pos_inf_s3      <= pos_inf_s2;
            neg_inf_s3      <= neg_inf_s2;
        end
    end

    // ==================== Stage 4: 规格化和舍入 ====================
    // LOD实例化
    logic [LOD_WIDTH-1:0] first_one_pos;
    logic                 no_ones_flag;

    lod #(
        .LEN(CSA_WIDTH)
    ) u_lod (
        .in_i(abs_accumulator_s4),
        .first_one_o(first_one_pos),
        .no_ones_o(no_ones_flag)
    );

    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            valid_s4           <= '0;
            result_sign_s4     <= '0;
            abs_accumulator_s4 <= '0;
            first_one_pos_s4   <= '0;
            no_ones_flag_s4    <= '0;
            max_exponent_s4    <= '0;
            is_inf_s4          <= '0;
            is_nan_s4          <= '0;
            is_zero_s4         <= '0;
            pos_inf_s4         <= '0;
            neg_inf_s4         <= '0;
        end else begin
            valid_s4           <= valid_s3;
            result_sign_s4     <= accumulator_s3[CSA_WIDTH-1];
            abs_accumulator_s4 <= accumulator_s3[CSA_WIDTH-1] ? (~accumulator_s3 + 1) : accumulator_s3;
            first_one_pos_s4   <= first_one_pos;
            no_ones_flag_s4    <= no_ones_flag;
            max_exponent_s4    <= max_exponent_s3;
            is_inf_s4          <= is_inf_s3;
            is_nan_s4          <= is_nan_s3;
            is_zero_s4         <= is_zero_s3;
            pos_inf_s4         <= pos_inf_s3;
            neg_inf_s4         <= neg_inf_s3;
        end
    end

    // ==================== 最终阶段：输出生成 ====================
    logic [           OUT_EWIDTH-1:0] leading_zeros;
    logic [  OUT_EWIDTH+GUARD_BITS:0] extended_max_exp;
    logic [OUT_EWIDTH+GUARD_BITS-1:0] norm_exponent;
    logic [              CSA_WIDTH:0] norm_significand;
    logic guard, round, sticky;
    logic                             round_up;
    logic [           OUT_MWIDTH-1:0] final_mantissa;
    logic [  OUT_SIGNIFICAND_WIDTH:0] mantissa_before_round;
    logic [  OUT_SIGNIFICAND_WIDTH:0] mantissa_after_round;
    logic [OUT_EWIDTH+GUARD_BITS-1:0] adjusted_exponent;
    logic exponent_overflow, exponent_underflow;
    logic any_inf, any_nan, any_zero;
    logic pos_inf_exists, neg_inf_exists, inf_cancel;
    logic                  result_is_zero;
    logic [OUT_EWIDTH-1:0] final_exponent;
    logic [OUT_MWIDTH-1:0] final_mantissa_processed;

    always_comb begin
        // 规格化处理 - 适配FP32输出
        leading_zeros = {3'b000, first_one_pos_s4[LOD_WIDTH-1:0]};  // 扩展到8位
        extended_max_exp = max_exponent_s4 + GUARD_BITS + 1;
        norm_exponent = (extended_max_exp > leading_zeros) ? extended_max_exp - leading_zeros : '0;

        // 规格化后的尾数
        norm_significand = (leading_zeros == 0) ? 
                          abs_accumulator_s4[CSA_WIDTH-1:RWIDTH] :
                          (abs_accumulator_s4 << leading_zeros);

        // IEEE 754最近偶数舍入 - 适配FP32精度
        guard = norm_significand[RWIDTH+1];
        round = norm_significand[RWIDTH];
        sticky = |norm_significand[RWIDTH-1:0];

        // 最近偶数舍入规则
        round_up = guard & (round | sticky | norm_significand[RWIDTH+2]);

        mantissa_before_round = {1'b0, norm_significand[CSA_WIDTH:CSA_WIDTH-OUT_SIGNIFICAND_WIDTH]};
        mantissa_after_round = mantissa_before_round + round_up;
        final_mantissa = mantissa_after_round[OUT_MWIDTH-1:0];

        // 调整指数（如果舍入导致进位）
        adjusted_exponent = norm_exponent + mantissa_after_round[OUT_SIGNIFICAND_WIDTH];

        // 异常处理 - 适配FP32范围
        exponent_overflow = (adjusted_exponent >= MAX_OUT_EXP);
        exponent_underflow = (adjusted_exponent == 0);

        any_inf = |is_inf_s4;
        any_nan = |is_nan_s4;
        any_zero = &is_zero_s4;  // 所有输入都是零

        pos_inf_exists = |pos_inf_s4;
        neg_inf_exists = |neg_inf_s4;
        inf_cancel = pos_inf_exists & neg_inf_exists;  // 正负无穷相消

        result_is_zero = no_ones_flag_s4 | (~|abs_accumulator_s4) | any_zero;

        // 处理下溢情况
        final_exponent = exponent_underflow ? OUT_EXP_ZEROS : adjusted_exponent[OUT_EWIDTH-1:0];
        final_mantissa_processed = exponent_underflow ? 
                                  (mantissa_after_round >> (leading_zeros - GUARD_BITS - 1)) :
                                  final_mantissa;
    end

    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            valid_out <= '0;
            result    <= '0;
            exception <= '0;
        end else begin
            valid_out <= valid_s4;
            exception <= any_nan | inf_cancel | exponent_overflow;

            if (any_nan) begin
                // 任何NaN输入都产生NaN输出
                result <= NAN;
            end else if (inf_cancel) begin
                // 正负无穷相消产生NaN
                result <= NAN;
            end else if (any_inf) begin
                // 有无穷输入且无相消，输出无穷
                if (pos_inf_exists & ~neg_inf_exists) begin
                    result <= {1'b0, OUT_EXP_ONES, OUT_MANT_ZEROS};  // +∞
                end else if (neg_inf_exists & ~pos_inf_exists) begin
                    result <= {1'b1, OUT_EXP_ONES, OUT_MANT_ZEROS};  // -∞
                end else begin
                    result <= NAN;  // 这种情况不应该发生，但为了安全
                end
            end else if (result_is_zero) begin
                // 结果为零
                result <= {result_sign_s4, OUT_EXP_ZEROS, OUT_MANT_ZEROS};
            end else if (exponent_overflow) begin
                // 指数溢出产生无穷
                result <= {result_sign_s4, OUT_EXP_ONES, OUT_MANT_ZEROS};
            end else begin
                // 正常情况
                result <= {result_sign_s4, final_exponent, final_mantissa_processed};
            end
        end
    end

endmodule
